﻿/*jshint browser:true*/
/// <reference path="../knockout-2.1.0.debug.js" />

define(['knockout', 'Sammy', 'moment', 'toastr', 'gfx/effects'], function (ko, Sammy, moment) {

    var addressFormatter = function () {
        return this.Street1 + ", " +
            this.Suburb + ", " +
            this.State + " " + this.Postcode;
    };
    var birthdayFromNow = function () {
        var birthday = moment(this.Birthday).year(moment().year());
        var isInFuture = birthday > moment() ? "is" : "was";
        return ("which " + isInFuture + " " + birthday.fromNow());
    };

    var updateDisplay = function () {
        $("#source").queueNext(function () {
            $("#source").quicksand($("#destination li"), {
                duration: 800,
                easing: 'easeInOutQuad',
                adjustHeight: false,
                useScaling: false
            }, function () {
            });
        });
    };

    var sortByLastName = function (x, y) {
        return x.LastName.localeCompare(y.LastName);
    };

    var sortByBirthDay = function (x, y) {
        var a = moment(x.Birthday).year(moment().year());
        var b = moment(y.Birthday).year(moment().year());
        var retval = 0;
        if (a > b) retval = 1;
        else if (a < b) retval = -1;
        return retval;
    };

    var updateModel = function (model) {
        $.extend(model, { Address: addressFormatter, BirthdayFromNow: birthdayFromNow });
        model.HasBeenSentVoucherThisYear = ko.observable(model.HasBeenSentVoucherThisYear || false);
        model.HasRedeemedVoucher = ko.observable(model.HasRedeemedVoucher || false);
    };

    return function (el) {
        var context = this;
        this.el = $(el);
        this.contactsView = this.el.find("#view-contacts");
        this.exportView = this.el.find("#export-contacts");

        this.url = App.urlBuilder("contacts");
        this.mailingUrl = App.urlBuilder("mailings");
        this.title = ko.observable("Contacts");
        this.subTitle = ko.observable("By Month");
        this.registrations = ko.observableArray([]);
        this.allRegistrations = [];
        this.selectedMonth = ko.observable(null);
        this.sortBy = ko.observable(null);
        this.searchText = ko.observable(null);
        this.forExport = ko.observableArray([]);
        this._updateUIVersion = 0;

        $("body").bind("delete-contact-confirmed", function (e) {
            var index = ko.utils.arrayIndexOf(context.selectedMonth().Registrations, e.contact);
            var indexAll = ko.utils.arrayIndexOf(context.allRegistrations, e.contact);
            if (index >= 0) {
                context.selectedMonth().Registrations.splice(index, 1);
                context.selectedMonth().ComputedList.remove(e.contact);
            }
            if (indexAll > 0) {
                context.allRegistrations.splice(indexAll, 1);
            }
            updateDisplay();
        });
        $("body").bind("update-contact", function (e) {
            updateModel(e.contact, context);
            var indexAll = ko.utils.arrayIndexOf(context.allRegistrations, e.oldContact || {});
            if (indexAll > -1) {
                ko.mapping.fromJS(e.contact, {}, context.allRegistrations[indexAll]);
                context.allRegistrations[indexAll] = e.contact;
            }
            $.each(context.registrations(), function (i, type) {
                var index = ko.utils.arrayIndexOf(type.Registrations, e.oldContact || {});
                if (index > -1) {
                    type.Registrations[index] = e.contact;
                    context.selectedMonth(type);
                } else if (type.Month == moment(e.contact.Birthday).format("MMMM")) {
                    type.Registrations.push(e.contact);
                    context.allRegistrations.push(e.contact);
                    type.ComputedList(type.Registrations.slice());
                    context.selectedMonth(type);
                }
            });
            $("#source li.flipped[data-id='" + e.contact.Id + "']").trigger("flip");
        });
        $("body").bind("update-by-id", function (e) {
            var oldContact = null;
            $.each(context.allRegistrations, function() {
                if (this.Id === e.contact.Id) {
                    oldContact = this;
                    return;
                }
            });
            context.el.trigger({ type: e.callback, oldContact: oldContact, contact: e.contact });
        });

        this.selectedMonthSorted = ko.computed(function () {
            var ar = context.selectedMonth();
            var s = context.sortBy();
            var search = context.searchText();

            if (typeof ar == 'undefined' || ar == null) return null;

            var updateDelegate = function () {
                ar.ComputedList = ar.ComputedList || ko.observableArray(ar.Registrations.slice());
                ar.ComputedList.removeAll();

                $.each(ar.Registrations, function (i, type) {
                    if (search != null && search.length > 0) {
                        if (type.FirstName.toLowerCase().indexOf(search.toLowerCase()) > -1 ||
                            type.LastName.toLowerCase().indexOf(search.toLowerCase()) > -1) {
                            ar.ComputedList.push(type);
                        }
                    } else {
                        ar.ComputedList.push(type);
                    }
                });

                var sortby = (s == "lastName" ? sortByLastName : sortByBirthDay);
                ar.ComputedList.sort(sortby);
                updateDisplay();
            };

            context._updateUIVersion++;

            var thisVersion = context._updateUIVersion;
            setTimeout(function () {
                if (thisVersion == context._updateUIVersion) {
                    updateDelegate.call(context);
                }
            }, 300);

            return ar;

        }, this);

        this.responded = function (d, event) {
            event.preventDefault();
            $.ajax({
                url: context.mailingUrl("ContactResponded"),
                dataType: 'json',
                type: "PUT",
                data: JSON.stringify({ Id: d.Id }),
                accept: 'application/json',
                contentType: 'application/json'
            }).success(function (data) {
                d.HasRedeemedVoucher(moment());
                $("#source li[data-id='" + d.Id + "']").trigger("flip");
                updateDisplay();
                toastr.success("Saved");
            }).fail(function () {
                toastr.error("Failed to save record :'(");
            });

        }.bind(this);

        this.deleteClicked = function (data, event) {
            event.preventDefault();
            context.el.trigger({ type: "delete-contact", contact: data });
        }.bind(this);

        this.editClicked = function (data, event) {
            event.preventDefault();
            context.el.trigger({ type: "edit-registration", contact: data });
        }.bind(this);

        this.exportClicked = function (data, event) {
            event.preventDefault();
            App.navigate("registrations", context.selectedMonth().Month, "export");
        }.bind(this);

        this.clearForExport = function (data, event) {
            event.preventDefault();
            App.navigate("registrations", context.selectedMonth().Month);
        }.bind(this);

        this.confirmExportClicked = function (d, event) {
            event.preventDefault();
            var contactIds = [];
            $.each(context.forExport(), function (i, type) {
                if (type.shouldExport() == true) {
                    contactIds.push(type.Id);
                }
            });
            $.ajax({
                url: context.mailingUrl("CreateForContacts"),
                dataType: 'json',
                type: "POST",
                data: JSON.stringify(contactIds),
                accept: 'application/json',
                contentType: 'application/json'
            }).success(function (data) {
                toastr.success('Mailings have been created!');
                $.each(context.forExport(), function (i, type) {
                    if (type.shouldExport() == true) {
                        type.HasBeenSentVoucherThisYear(moment());
                    }
                });
                App.navigate("registrations", context.selectedMonth().Month);
            }).fail(function () {
                toastr.error("Failed to create mailing records, something went wrong :'(");
            });

        }.bind(this);

        this.loadData = function () {
            var loaded = $.Deferred();
            $.ajax({
                url: context.url("GetRegistrationsByMonth"),
                dataType: 'json',
                type: "GET",
                accept: 'application/json',
                contentType: 'application/json'
            }).success(function (data) {
                context.registrations.removeAll();
                context.registrations.push({ Month: "All", Registrations: context.allRegistrations, ComputedList: ko.observableArray(context.allRegistrations.slice()) });
                $.each(data, function (i, type) {
                    $.each(type.Registrations, function () {
                        updateModel(this, context);
                        context.allRegistrations.push(this);
                    });
                    type.ComputedList = type.ComputedList || ko.observableArray(type.Registrations.slice());
                    context.registrations.push(type);
                });
                loaded.resolve();
            }).fail(function () { loaded.reject(); });
            return loaded.promise();
        };

        this.populateRegistrations = function (month) {
            $.each(context.registrations(), function (i, type) {
                if (type.Month == month) {
                    context.selectedMonth(type);
                }
            });
            updateDisplay();
        }.bind(this);

        this.routes = function () {
            return {
                "#/": function () {
                    context.loadData();
                    context.selectedMonth(null);
                },
                "#/registrations/:month": function (s) {
                    context.forExport.removeAll();

                    if (context.registrations().length == 0) {
                        context.loadData().done(function () { context.populateRegistrations(s.params.month); });
                    }
                    else {
                        context.contactsView
                            .queueNext(function () {
                                if (context.exportView.is(":visible")) {
                                    context.exportView.gfxRaisedOut().hide();
                                }
                            })
                            .queueNext(function () {
                                if (context.contactsView.is(":visible") == false) {
                                    context.contactsView.gfxRaisedIn();
                                    context.contactsView.removeAttr("style");
                                }
                            }).queueNext(function () {
                                context.populateRegistrations(s.params.month);
                            });
                    }

                },
                "#/registrations/:month/export": function (s) {
                    context.forExport.removeAll();
                    $.each(context.selectedMonth().ComputedList(), function (i, type) {
                        type.shouldExport = ko.observable(true);
                        context.forExport.push(type);
                    });

                    context.exportView
                        .queueNext(function () {
                            context.contactsView.gfxRaisedOut().hide();
                        })
                        .queueNext(function () {
                            context.exportView.gfxRaisedIn().removeAttr("style");
                        });

                }
            };
        };
    };

});